<template>
	<rui-pages>
		<view class="ota">
			<view class="ota_title">
				{{message.title}}
			</view>
			<view class="ota_desc">
				{{message.desc || ''}}
			</view>

			<view class="ota_chart" v-if="ready_status">
				<rui-charts-wave :color="color" :progress="progress" size="300rpx"></rui-charts-wave>
			</view>
			<view class="" v-else>
				<button class="ota_btn" @click="connect" v-if="open_status">
					连接蓝牙
				</button>
				<button class="ota_btn" @click="start" :disabled="!connect_status" v-else>
					{{btn_text}}
				</button>
			</view>
		</view>


	</rui-pages>
</template>

<script setup>
	import {
		ref
	} from "vue"

	import {
		getVersion
	} from "@/common/api.js"

	import {
		onLoad,
		onUnload
	} from "@dcloudio/uni-app"

	import {
		_setBuffer,
		_handleBuffer
	} from "@/util/common.js"

	import ble from "@/util/ble.js"
	import {
		productStore
	} from "@/store"

	let product = productStore()

	let color = ref("#67c8f2")
	let progress = ref(0)
	let connect_status = ref(false)
	let message = ref({})


	let obj = {};
	let new_ver = ""
	let old_ver = ""
	let btn_text = ref("请触摸指纹激活水杯");
	let btn_status = ref(true)
	let option = {}
	//刚进入界面
	let open_status = ref(true)

	let ready_status = ref(false)

	//升级文件地址
	// let url = ""

	let upload_file;
	let upload_data = [];
	let upload_length = 0;

	let erase_addr = 0;
	let erase_pages = 0;
	let erase_count = 0;


	let packet = 500
	let upload_pages = 0
	let upload_addr = 0;

	let crc_value = 0;

	const START = "01"
	const ERASE = "03"
	const UPLOAD = "05"
	const END = "09"




	//退出页面
	onUnload(() => {
		ble.close()
		//关闭屏幕常亮
		uni.setKeepScreenOn({
			keepScreenOn: false
		});
		ble.watch = function() {}
		ble.error = function() {}
	})

	onLoad(() => {
		//保持屏幕常亮
		uni.setKeepScreenOn({
			keepScreenOn: true
		});

		getVerInfo()

		//监听事件
		ble.error = (event, d) => {
			console.log(event, d)
			if (event == 'connection' || event == 'services') {
				ble.connect();
			}
		}
		ble.watch = (event, d) => {
			console.log(event, d)
			if (event == 'close') {
				//连接蓝牙
				// ble.connect()
			}
			if (event == 'state2') {
				btn_text.value = `请触摸指纹激活水杯 ${d.remainder}s`
			}

			if (event == 'state') {
				connect_status.value = d.connected
				btn_text.value = d.connected ? "开始升级" : "请触摸指纹激活水杯"
			}
			if (event == 'start') {

			}
			if (event == 'notify') {
				if (d.command == START) {
					//存储起始地址
					upload_addr = erase_addr = parseInt(d.data.slice(0, 4).join(""), 16);
					erase()
					console.log('存储起始地址', d.data.slice(0, 4), erase_addr)
				}
			}
		}
	})

	const connect = () => {
		open_status.value = false;
		//断开连接
		ble.close()
		ble.config({
			deviceId: product.getInfo.deviceId,
			characteristic: {
				serviceId: "02F00000-0000-0000-0000-00000000FE00",
				writeId: "02F00000-0000-0000-0000-00000000FF01",
				notifyId: "02F00000-0000-0000-0000-00000000FF02",
			},
		})
		setTimeout(_ => {
			ble.connect()
		}, 1000)


	}


	const getVerInfo = (callback) => {
		getVersion({
			product_id: product.getInfo.product_id
		}).then(res => {
			// url = res.data.path;
			//检测版本
			if (product.getVersion >= res.data.version) {
				message.value = {
					title: `您已是最新固件版本`,
					desc: `您当前版本${product.getVersion},无需更新请返回。`
				}
				btn_text.value = "无需更新"
			} else {
				message.value = {
					title: `最新固件版本${res.data.version}`,
					desc: `您当前版本${product.getVersion}, 新版本${res.data.content}。`
				}
				downFile(res.data.path);
				if (typeof callback == 'function') {
					callback()
				}
			}

		})
	}

	const start = () => {
		message.value = {
			title: `正在升级中,请耐心等候...`,
			desc: `固件升级过程中，请勿关闭页面否者会升级失败。`
		}
		ready_status.value = true;

		ble.send(createBuffer({
			command: START,
			len: 2
		}), '', 1000)
	}


	const downFile = (url) => {
		uni.request({
			url,
			method: 'GET',
			responseType: 'arraybuffer', // 设置响应类型为 arraybuffer  
			success: function(res) {
				if (res.statusCode === 200) {
					let binDataView = _setBuffer(res.data, packet)
					upload_data = binDataView.data;
					upload_length = binDataView.len;
					upload_pages = upload_data.length;
					crc_value = binDataView.crc;

					// erase_pages = binDataView.len / 4096;
					erase_pages = Math.floor(upload_length / 4096)
					if((upload_length % 4096) != 1) {
						count++;
					}
					
					console.log('crc', crc_value, binDataView.len, erase_pages, upload_pages)
				} else {
					console.error('获取文件失败', res);
				}
			},
			fail: function(err) {
				console.error('请求失败', err);
			}
		});
	}



	/**
	 * 擦除内存地址
	 */

	const erase = () => {
		
		let buffer = createBuffer({
			command: ERASE,
			len: 4,
			addr: erase_list[erase_count]
		})
		ble.send(buffer, () => {
			if (erase_count < erase_pages) {
				erase()
			} else {
				// upload()
				console.log('开始升级')
			}
			erase_count++
		}, 80)
	}


	/**
	 * 上传数据
	 */

	let upload_count = 0
	const upload = () => {
		let len = packet + 6
		let buffer = createBuffer({
			command: UPLOAD,
			len,
			addr: upload_addr + upload_count * packet,
			packet,
			data: upload_data[upload_count]
		})
		ble.send(buffer, () => {
			//完成进度
			progress.value = (upload_count / upload_pages * 100) >> 0;
			if (upload_count < upload_pages) {
				upload()
			} else {
				console.log("升级结束")
				end()
			}

			upload_count++;

		}, 100)

	}


	/** 
	 * 完成重启
	 */
	const end = () => {
		let buffer = createBuffer({
			command: END,
			len: 8,
			bin_length: upload_length,
			crc: crc_value
		})
		ble.send(buffer, () => {
			message.value = {
				title: `恭喜您升级成功`,
				desc: `您已成功升级到${new_ver}版本，关闭页面重启设备。`
			}
		}, 500)
	}


	const createBuffer = (option) => {
		option.command = _handleBuffer(option.command, 1)
		option.len = _handleBuffer(option.len, 2)
		if (option.addr || option.addr == 0) {
			option.addr = _handleBuffer(option.addr, 4)
		}

		let hex_str = [];
		switch (option.command[0]) {
			case START:
				hex_str = [...option.command, ...option.len, '00000000']
				break;
			case ERASE:
				hex_str = [...option.command, ...option.len, ...option.addr]
				break;
			case UPLOAD:
				option.packet = _handleBuffer(option.packet, 2)
				hex_str = [...option.command, ...option.len, ...option.addr, ...option.packet, ...option.data]
				break;
			case END:
				option.crc = _handleBuffer(option.crc, 4)
				option.bin_length = _handleBuffer(option.bin_length, 4)
				hex_str = [...option.command, ...option.len, ...option.bin_length, ...option.crc]
				break;
		}
		console.log('hex_str', option, hex_str)
		let typedArray = new Uint8Array(hex_str.map(function(h) {
			return parseInt(h, 16)
		}))
		return typedArray.buffer
	}
</script>

<style lang="scss" scoped>
	.ota {
		margin: 150rpx 30rpx;

		&_btn {
			background: #67c8f2;
			width: 80%;
			height: 80rpx;
			color: #fff;
			text-align: center;
			line-height: 80rpx;
			border-radius: 20rpx;
			margin: 100rpx auto;

			&::after {
				border: none;
			}

		}

		&_title {
			text-align: center;
			font-weight: bold;
			font-size: 38rpx;
		}

		&_desc {
			font-size: 24rpx;
			color: #999;
			text-align: center;
			margin-top: 10rpx;
		}

		&_chart {
			display: flex;
			justify-content: center;
			margin-top: 150rpx;
		}
	}
</style>